--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
docs/meshchatx_linux_sandbox.md legacy/win7 (159b2358) Text, 6.61 KB
Tc9d1d9# MeshChatX on Linux: Firejail and Bubblewrap
This page shows how to run **`meshchatx`** under **Firejail** or **Bubblewrap** (Ta5d6ff`bwrap`) on Linux. The legacy CLI name **`meshchat`** installs the same entry point and can be substituted in these examples. Use this when you install MeshChatX natively (wheel, package, or Poetry) and want an extra layer of filesystem and process isolation compared to running the binary directly.
These tools do **not** replace a full virtual machine or hardware-enforced boundary. They reduce exposure of your home directory and other paths the process can write to, when you configure them with tight whitelists or bind mounts.
**Containers:** If you already run MeshChatX with Docker or Podman, that is a different isolation model; this document is aimed at **host-installed** Ta5d6ff`meshchatx` (or Ta5d6ff`meshchat`).
Tc9d1d9## Prerequisites
Install one or both from your distribution:
Tff7b72- **Firejail:** package name is usually Ta5d6ff`firejail`.
Tff7b72- **Bubblewrap:** package name is usually Ta5d6ff`bubblewrap`; the binary is Ta5d6ff`bwrap`.
You need a working **`meshchatx`** on your Ta5d6ff`PATH` (for example after Ta5d6ff`pipx install`, Ta5d6ff`pip install --user`, or a distro package). The **`meshchat`** command is the same binary if both entry points are installed.
Pick a **dedicated data directory** for sandboxed runs so you do not mix permissions or policies with a non-sandboxed install. The examples below use:
Ta5d6ff```Ta5d6ffbash
Te6edf3DATATff7b72=Ta5d6ff"Tffd700${Te6edf3XDG_DATA_HOMETff7b72:-Te6edf3$HOMETb4b4b4/.local/shareTffd700}Ta5d6ff/meshchatx-sandboxTa5d6ff"
mkdir -p Ta5d6ff"Te6edf3$DATATa5d6ff/storageTa5d6ff" Ta5d6ff"Te6edf3$DATATa5d6ff/.reticulumTa5d6ff"
Ta5d6ff```
Adjust paths if you prefer another location.
Tc9d1d9## Firejail
Firejail applies a profile (or defaults) on top of your command. For MeshChatX you typically want:
Tff7b72- **Network** left available so Reticulum and the web UI can work (do not use Ta5d6ff`--net=none` unless you know you need it).
Tff7b72- **Writable** only your chosen data directory (and anything else the app truly needs).
Tc9d1d9### Installed `meshchatx` (pip, pipx, or system package)
Ta5d6ff```Ta5d6ffbash
Te6edf3DATATff7b72=Ta5d6ff"Tffd700${Te6edf3XDG_DATA_HOMETff7b72:-Te6edf3$HOMETb4b4b4/.local/shareTffd700}Ta5d6ff/meshchatx-sandboxTa5d6ff"
mkdir -p Ta5d6ff"Te6edf3$DATATa5d6ff/storageTa5d6ff" Ta5d6ff"Te6edf3$DATATa5d6ff/.reticulumTa5d6ff"
firejail --quiet Tffea00\
--whitelistTff7b72=Ta5d6ff"Te6edf3$DATATa5d6ff" Tffea00\
meshchatx --headless --host T79c0ff127.0.0.1 Tffea00\
--storage-dirTff7b72=Ta5d6ff"Te6edf3$DATATa5d6ff/storageTa5d6ff" Tffea00\
--reticulum-config-dirTff7b72=Ta5d6ff"Te6edf3$DATATa5d6ff/.reticulumTa5d6ff"
Ta5d6ff```
If the default profile blocks something MeshChatX needs, you can start from a looser base and tighten later, for example:
Ta5d6ff```Ta5d6ffbash
firejail --noprofile --whitelistTff7b72=Ta5d6ff"Te6edf3$DATATa5d6ff" Tffea00\
meshchatx --headless --host T79c0ff127.0.0.1 Tffea00\
--storage-dirTff7b72=Ta5d6ff"Te6edf3$DATATa5d6ff/storageTa5d6ff" Tffea00\
--reticulum-config-dirTff7b72=Ta5d6ff"Te6edf3$DATATa5d6ff/.reticulumTa5d6ff"
Ta5d6ff```
Ta5d6ff`--noprofile` disables many Firejail restrictions; treat it as a stepping stone, not the final hardening.
Tc9d1d9### From source with UV
Poetry needs the project tree and the virtualenv. Example:
Ta5d6ff```Ta5d6ffbash
Tffa657cd /path/to/reticulum-meshchatX
Te6edf3DATATff7b72=Ta5d6ff"Tffd700${Te6edf3XDG_DATA_HOMETff7b72:-Te6edf3$HOMETb4b4b4/.local/shareTffd700}Ta5d6ff/meshchatx-sandboxTa5d6ff"
Te6edf3VENVTff7b72=Ta5d6ff"Tff7b72$(Tffa657pwdTff7b72)Ta5d6ff/.venvTa5d6ff"
mkdir -p Ta5d6ff"Te6edf3$DATATa5d6ff/storageTa5d6ff" Ta5d6ff"Te6edf3$DATATa5d6ff/.reticulumTa5d6ff"
firejail --quiet Tffea00\
--whitelistTff7b72=Ta5d6ff"Tff7b72$(Tffa657pwdTff7b72)Ta5d6ff" Tffea00\
--whitelistTff7b72=Ta5d6ff"Te6edf3$VENVTa5d6ff" Tffea00\
--whitelistTff7b72=Ta5d6ff"Te6edf3$DATATa5d6ff" Tffea00\
uv run python -m meshchatx.meshchat --headless --host T79c0ff127.0.0.1 Tffea00\
--storage-dirTff7b72=Ta5d6ff"Te6edf3$DATATa5d6ff/storageTa5d6ff" Tffea00\
--reticulum-config-dirTff7b72=Ta5d6ff"Te6edf3$DATATa5d6ff/.reticulumTa5d6ff"
Ta5d6ff```
You may need extra Ta5d6ff`--whitelist=` entries if UV or dependencies read config elsewhere (for example under Ta5d6ff`$HOME/.config`).
Tc9d1d9### USB serial (RNode or similar)
If Reticulum talks to a radio over a serial device, Firejail may need explicit access to TTY devices, for example:
Ta5d6ff```Ta5d6ffbash
firejail --noblacklistTff7b72=/dev/ttyACM0 --noblacklistTff7b72=/dev/ttyUSB0 Tffea00\
...
Ta5d6ff```
Use the device nodes your system actually exposes (Ta5d6ff`dmesg`, Ta5d6ff`ls /dev/tty*`).
Tc9d1d9## Bubblewrap (`bwrap`)
Bubblewrap does not ship profiles; you list every mount and option. The pattern below keeps the **whole root filesystem read-only**, mounts a **writable tmpfs** on Ta5d6ff`/tmp`, and makes **only** your data directory writable at its normal path. **Network namespaces are not changed**, so Reticulum and TCP/UDP behave like an unsandboxed process unless you add Ta5d6ff`--unshare-net` (which usually breaks mesh networking).
Tc9d1d9### Installed `meshchatx`
Ta5d6ff```Ta5d6ffbash
Te6edf3DATATff7b72=Ta5d6ff"Tffd700${Te6edf3XDG_DATA_HOMETff7b72:-Te6edf3$HOMETb4b4b4/.local/shareTffd700}Ta5d6ff/meshchatx-sandboxTa5d6ff"
mkdir -p Ta5d6ff"Te6edf3$DATATa5d6ff/storageTa5d6ff" Ta5d6ff"Te6edf3$DATATa5d6ff/.reticulumTa5d6ff"
Tffa657exec bwrap Tffea00\
--die-with-parent Tffea00\
--new-session Tffea00\
--proc /proc Tffea00\
--dev /dev Tffea00\
--ro-bind / / Tffea00\
--tmpfs /tmp Tffea00\
--bind Ta5d6ff"Te6edf3$DATATa5d6ff" Ta5d6ff"Te6edf3$DATATa5d6ff" Tffea00\
--uid Ta5d6ff"Tff7b72$(id -uTff7b72)Ta5d6ff" --gid Ta5d6ff"Tff7b72$(id -gTff7b72)Ta5d6ff" Tffea00\
meshchatx --headless --host T79c0ff127.0.0.1 Tffea00\
--storage-dirTff7b72=Ta5d6ff"Te6edf3$DATATa5d6ff/storageTa5d6ff" Tffea00\
--reticulum-config-dirTff7b72=Ta5d6ff"Te6edf3$DATATa5d6ff/.reticulumTa5d6ff"
Ta5d6ff```
Notes:
Tff7b72- If Ta5d6ff`meshchatx` lives only inside a venv that is **not** under Ta5d6ff`$DATA`, the read-only root still allows **reading** that path; you do not have to bind-mount the venv separately unless you also need writes there.
Tff7b72- Distributions that merge Ta5d6ff`/` and Ta5d6ff`/usr` (merged-usr) still work with Ta5d6ff`--ro-bind / /` on typical glibc setups. If Ta5d6ff`bwrap` fails with missing library paths, add the extra Ta5d6ff`--ro-bind` lines your distro documents (for example Ta5d6ff`/lib64`).
Tc9d1d9### From source with UV
Bind the repository and the UV venv read-only, and keep Ta5d6ff`DATA` writable:
Ta5d6ff```Ta5d6ffbash
Tffa657cd /path/to/reticulum-meshchatX
Te6edf3DATATff7b72=Ta5d6ff"Tffd700${Te6edf3XDG_DATA_HOMETff7b72:-Te6edf3$HOMETb4b4b4/.local/shareTffd700}Ta5d6ff/meshchatx-sandboxTa5d6ff"
Te6edf3VENVTff7b72=Ta5d6ff"Tff7b72$(Tffa657pwdTff7b72)Ta5d6ff/.venvTa5d6ff"
mkdir -p Ta5d6ff"Te6edf3$DATATa5d6ff/storageTa5d6ff" Ta5d6ff"Te6edf3$DATATa5d6ff/.reticulumTa5d6ff"
Te6edf3PROJTff7b72=Ta5d6ff"Tff7b72$(Tffa657pwdTff7b72)Ta5d6ff"
Tffa657exec bwrap Tffea00\
--die-with-parent Tffea00\
--new-session Tffea00\
--proc /proc Tffea00\
--dev /dev Tffea00\
--ro-bind / / Tffea00\
--tmpfs /tmp Tffea00\
--bind Ta5d6ff"Te6edf3$DATATa5d6ff" Ta5d6ff"Te6edf3$DATATa5d6ff" Tffea00\
--ro-bind Ta5d6ff"Te6edf3$PROJTa5d6ff" Ta5d6ff"Te6edf3$PROJTa5d6ff" Tffea00\
--ro-bind Ta5d6ff"Te6edf3$VENVTa5d6ff" Ta5d6ff"Te6edf3$VENVTa5d6ff" Tffea00\
--uid Ta5d6ff"Tff7b72$(id -uTff7b72)Ta5d6ff" --gid Ta5d6ff"Tff7b72$(id -gTff7b72)Ta5d6ff" Tffea00\
--setenv PATH Ta5d6ff"Te6edf3$VENVTa5d6ff/bin:Te6edf3$PATHTa5d6ff" Tffea00\
--chdir Ta5d6ff"Te6edf3$PROJTa5d6ff" Tffea00\
uv run python -m meshchatx.meshchat --headless --host T79c0ff127.0.0.1 Tffea00\
--storage-dirTff7b72=Ta5d6ff"Te6edf3$DATATa5d6ff/storageTa5d6ff" Tffea00\
--reticulum-config-dirTff7b72=Ta5d6ff"Te6edf3$DATATa5d6ff/.reticulumTa5d6ff"
Ta5d6ff```
Ta5d6ff`uv` itself must be reachable on Ta5d6ff`PATH` inside the sandbox (often under Ta5d6ff`/usr` or Ta5d6ff`$HOME/.local/bin`, both visible with Ta5d6ff`--ro-bind / /`). If Ta5d6ff`uv run` fails because it cannot read Ta5d6ff`~/.cache/uv`, add a read-only bind for that directory or invoke the venv interpreter directly instead of Ta5d6ff`uv run`:
Ta5d6ff```Ta5d6ffbash
Tffa657exec bwrap Tffea00\
... same mounts as above ... Tffea00\
--setenv PATH Ta5d6ff"Te6edf3$VENVTa5d6ff/bin:Te6edf3$PATHTa5d6ff" Tffea00\
--chdir Ta5d6ff"Te6edf3$PROJTa5d6ff" Tffea00\
meshchatx --headless --host T79c0ff127.0.0.1 Tffea00\
--storage-dirTff7b72=Ta5d6ff"Te6edf3$DATATa5d6ff/storageTa5d6ff" Tffea00\
--reticulum-config-dirTff7b72=Ta5d6ff"Te6edf3$DATATa5d6ff/.reticulumTa5d6ff"
Ta5d6ff```
(Use the Ta5d6ff`meshchatx` script, the legacy Ta5d6ff`meshchat` alias, or Ta5d6ff`python -m` entry point from Ta5d6ff`$VENV/bin` if your install exposes it there.)
Tc9d1d9### USB serial under Bubblewrap
You may need a clearer view of devices than the minimal Ta5d6ff`--dev /dev` provides. Options include Ta5d6ff`--dev-bind /dev /dev` (broader device exposure) or binding only the specific character device. Balance convenience against attack surface.
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────